/** @file

  Internal definitions for the virtio-net driver, which produces Simple Network
  Protocol instances for virtio-net devices.

  Copyright (C) 2013, Red Hat, Inc.
  Copyright (c) 2017, AMD Inc, All rights reserved.<BR>

  SPDX-License-Identifier: BSD-2-Clause-Patent
**/

#ifndef _VIRTIO_NET_DXE_H_
#define _VIRTIO_NET_DXE_H_

#include <IndustryStandard/VirtioNet.h>
#include <Library/DebugLib.h>
#include <Library/VirtioLib.h>
#include <Protocol/ComponentName.h>
#include <Protocol/ComponentName2.h>
#include <Protocol/DevicePath.h>
#include <Protocol/DriverBinding.h>
#include <Protocol/SimpleNetwork.h>
#include <Library/OrderedCollectionLib.h>

#define VNET_SIG SIGNATURE_32 ('V', 'N', 'E', 'T')

//
// maximum number of pending packets, separately for each direction
//
#define VNET_MAX_PENDING 64

//
// State diagram:
//
//                  |     ^
//                  |     |
//        BindingStart  BindingStop
//        +SnpPopulate    |
//        ++GetFeatures   |
//                  |     |
//                  v     |
//                +---------+    virtio-net device is reset, no resources are
//                | stopped |    allocated for traffic, but MAC address has
//                +---------+    been retrieved
//                  |     ^
//                  |     |
//            SNP.Start SNP.Stop
//                  |     |
//                  v     |
//                +---------+
//                | started |    functionally identical to stopped
//                +---------+
//                  |     ^
//                  |     |
//       SNP.Initialize SNP.Shutdown
//                  |     |
//                  v     |
//              +-------------+  Virtio-net setup complete, including DRIVER_OK
//              | initialized |  bit. The receive queue is populated with
//              +-------------+  requests; McastIpToMac, GetStatus, Transmit,
//                               Receive are callable.
//

typedef struct {
  //
  // Parts of this structure are initialized / torn down in various functions
  // at various call depths. The table to the right should make it easier to
  // track them.
  //
  //                          field              init function
  //                          ------------------ ------------------------------
  UINT32                      Signature;         // VirtioNetDriverBindingStart
  VIRTIO_DEVICE_PROTOCOL      *VirtIo;           // VirtioNetDriverBindingStart
  EFI_SIMPLE_NETWORK_PROTOCOL Snp;               // VirtioNetSnpPopulate
  EFI_SIMPLE_NETWORK_MODE     Snm;               // VirtioNetSnpPopulate
  EFI_EVENT                   ExitBoot;          // VirtioNetSnpPopulate
  EFI_DEVICE_PATH_PROTOCOL    *MacDevicePath;    // VirtioNetDriverBindingStart
  EFI_HANDLE                  MacHandle;         // VirtioNetDriverBindingStart

  VRING                       RxRing;            // VirtioNetInitRing
  VOID                        *RxRingMap;        // VirtioRingMap and
                                                 // VirtioNetInitRing
  UINT8                       *RxBuf;            // VirtioNetInitRx
  UINT16                      RxLastUsed;        // VirtioNetInitRx
  UINTN                       RxBufNrPages;      // VirtioNetInitRx
  EFI_PHYSICAL_ADDRESS        RxBufDeviceBase;   // VirtioNetInitRx
  VOID                        *RxBufMap;         // VirtioNetInitRx

  VRING                       TxRing;            // VirtioNetInitRing
  VOID                        *TxRingMap;        // VirtioRingMap and
                                                 // VirtioNetInitRing
  UINT16                      TxMaxPending;      // VirtioNetInitTx
  UINT16                      TxCurPending;      // VirtioNetInitTx
  UINT16                      *TxFreeStack;      // VirtioNetInitTx
  VIRTIO_1_0_NET_REQ          *TxSharedReq;      // VirtioNetInitTx
  VOID                        *TxSharedReqMap;   // VirtioNetInitTx
  UINT16                      TxLastUsed;        // VirtioNetInitTx
  ORDERED_COLLECTION          *TxBufCollection;  // VirtioNetInitTx
} VNET_DEV;


//
// In order to avoid duplication of interface documentation, please find all
// leading comments near the respective function / variable definitions (not
// the declarations here), which is where your code editor of choice takes you
// anyway when jumping to a function.
//

//
// utility macros
//
#define VIRTIO_NET_FROM_SNP(SnpPointer) \
        CR (SnpPointer, VNET_DEV, Snp, VNET_SIG)

#define VIRTIO_CFG_WRITE(Dev, Field, Value)  ((Dev)->VirtIo->WriteDevice (  \
                                                (Dev)->VirtIo,              \
                                                OFFSET_OF_VNET (Field),     \
                                                SIZE_OF_VNET (Field),       \
                                                (Value)                     \
                                                ))

#define VIRTIO_CFG_READ(Dev, Field, Pointer) ((Dev)->VirtIo->ReadDevice (   \
                                                (Dev)->VirtIo,              \
                                                OFFSET_OF_VNET (Field),     \
                                                SIZE_OF_VNET (Field),       \
                                                sizeof *(Pointer),          \
                                                (Pointer)                   \
                                                ))

//
// component naming
//
extern EFI_COMPONENT_NAME_PROTOCOL gVirtioNetComponentName;
extern EFI_COMPONENT_NAME2_PROTOCOL gVirtioNetComponentName2;

//
// driver binding
//
extern EFI_DRIVER_BINDING_PROTOCOL gVirtioNetDriverBinding;

//
// member functions implementing the Simple Network Protocol
//
EFI_STATUS
EFIAPI
VirtioNetStart (
  IN EFI_SIMPLE_NETWORK_PROTOCOL *This
  );

EFI_STATUS
EFIAPI
VirtioNetStop (
  IN EFI_SIMPLE_NETWORK_PROTOCOL *This
  );

EFI_STATUS
EFIAPI
VirtioNetInitialize (
  IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
  IN UINTN                       ExtraRxBufferSize  OPTIONAL,
  IN UINTN                       ExtraTxBufferSize  OPTIONAL
  );

EFI_STATUS
EFIAPI
VirtioNetReset (
  IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
  IN BOOLEAN                     ExtendedVerification
  );

EFI_STATUS
EFIAPI
VirtioNetShutdown (
  IN EFI_SIMPLE_NETWORK_PROTOCOL *This
  );

EFI_STATUS
EFIAPI
VirtioNetReceiveFilters (
  IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
  IN UINT32                      Enable,
  IN UINT32                      Disable,
  IN BOOLEAN                     ResetMCastFilter,
  IN UINTN                       MCastFilterCnt    OPTIONAL,
  IN EFI_MAC_ADDRESS             *MCastFilter      OPTIONAL
  );

EFI_STATUS
EFIAPI
VirtioNetStationAddress (
  IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
  IN BOOLEAN                     Reset,
  IN EFI_MAC_ADDRESS             *New OPTIONAL
  );

EFI_STATUS
EFIAPI
VirtioNetStatistics (
  IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
  IN BOOLEAN                     Reset,
  IN OUT UINTN                   *StatisticsSize   OPTIONAL,
  OUT EFI_NETWORK_STATISTICS     *StatisticsTable  OPTIONAL
  );

EFI_STATUS
EFIAPI
VirtioNetMcastIpToMac (
  IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
  IN BOOLEAN                     IPv6,
  IN EFI_IP_ADDRESS              *Ip,
  OUT EFI_MAC_ADDRESS            *Mac
  );

EFI_STATUS
EFIAPI
VirtioNetNvData (
  IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
  IN BOOLEAN                     ReadWrite,
  IN UINTN                       Offset,
  IN UINTN                       BufferSize,
  IN OUT VOID                    *Buffer
  );

EFI_STATUS
EFIAPI
VirtioNetGetStatus (
  IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
  OUT UINT32                     *InterruptStatus OPTIONAL,
  OUT VOID                       **TxBuf OPTIONAL
  );

EFI_STATUS
EFIAPI
VirtioNetTransmit (
  IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
  IN UINTN                       HeaderSize,
  IN UINTN                       BufferSize,
  IN /* +OUT! */ VOID            *Buffer,
  IN EFI_MAC_ADDRESS             *SrcAddr  OPTIONAL,
  IN EFI_MAC_ADDRESS             *DestAddr OPTIONAL,
  IN UINT16                      *Protocol OPTIONAL
  );

EFI_STATUS
EFIAPI
VirtioNetReceive (
  IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
  OUT UINTN                      *HeaderSize OPTIONAL,
  IN OUT UINTN                   *BufferSize,
  OUT VOID                       *Buffer,
  OUT EFI_MAC_ADDRESS            *SrcAddr    OPTIONAL,
  OUT EFI_MAC_ADDRESS            *DestAddr   OPTIONAL,
  OUT UINT16                     *Protocol   OPTIONAL
  );

//
// utility functions shared by various SNP member functions
//
VOID
EFIAPI
VirtioNetShutdownRx (
  IN OUT VNET_DEV *Dev
  );

VOID
EFIAPI
VirtioNetShutdownTx (
  IN OUT VNET_DEV *Dev
  );

VOID
EFIAPI
VirtioNetUninitRing (
  IN OUT VNET_DEV *Dev,
  IN OUT VRING    *Ring,
  IN     VOID     *RingMap
  );

//
// utility functions to map caller-supplied Tx buffer system physical address
// to a device address and vice versa
//
EFI_STATUS
EFIAPI
VirtioNetMapTxBuf (
  IN  VNET_DEV              *Dev,
  IN  VOID                  *Buffer,
  IN  UINTN                 NumberOfBytes,
  OUT EFI_PHYSICAL_ADDRESS  *DeviceAddress
  );

EFI_STATUS
EFIAPI
VirtioNetUnmapTxBuf (
  IN  VNET_DEV              *Dev,
  OUT VOID                  **Buffer,
  IN  EFI_PHYSICAL_ADDRESS  DeviceAddress
  );

INTN
EFIAPI
VirtioNetTxBufMapInfoCompare (
  IN CONST VOID *UserStruct1,
  IN CONST VOID *UserStruct2
  );

INTN
EFIAPI
VirtioNetTxBufDeviceAddressCompare (
  IN CONST VOID *StandaloneKey,
  IN CONST VOID *UserStruct
  );


//
// event callbacks
//
VOID
EFIAPI
VirtioNetIsPacketAvailable (
  IN  EFI_EVENT Event,
  IN  VOID      *Context
  );

VOID
EFIAPI
VirtioNetExitBoot (
  IN  EFI_EVENT Event,
  IN  VOID      *Context
  );

#endif // _VIRTIO_NET_DXE_H_
